
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/init.h>
#include <linux/fs.h>
#include <linux/delay.h>
#include <linux/poll.h>
#include <linux/mutex.h>
#include <linux/wait.h>
#include <linux/uaccess.h>
#include <linux/device.h>
#include <asm/io.h>



static int major;//主设备号
static struct class *led_class;

/* registers  寄存器指针*/
// IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 地址：0x02290000 + 0x14
static volatile unsigned int *IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3;

// GPIO5_GDIR 地址：0x020AC004
static volatile unsigned int *GPIO5_GDIR;

//GPIO5_DR 地址：0x020AC000
static volatile unsigned int *GPIO5_DR;


static ssize_t led_write(struct file *filp, const char __user *buf,
			 size_t count, loff_t *ppos)
{
	char val;
	int ret;
	/* copy_from_user : 从app获得数据 */
	ret = copy_from_user(&val, buf, 1);

	/* to set gpio register: out 1/0 */
	if (val)
	{
		/* set gpio to let led on */
		*GPIO5_DR &= ~(1<<3);//输出0
	}
	else
	{
		/* set gpio to let led off */
		*GPIO5_DR |= (1<<3);//输出1
	}
	return 1;
}

static int led_open(struct inode *inode, struct file *filp)
{
	/* enable gpio  imx6ull默认已经使能了  */
	//configure pin as gpio  设置为GPIO
	 *IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 &= ~0xf;//先清除
	 *IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 |= 0x5;//再赋值101
	//configure gpio as output  设置为输出
	*GPIO5_GDIR |= (1<<3);
	return 0;
}


//file_operations结构体
static struct file_operations led_fops = {
	.owner		= THIS_MODULE,
	.write		= led_write,
	.open		= led_open,
};


/* 入口函数 */
static int __init led_init(void)
{
    printk("%s %s %d\n", __FILE__, __FUNCTION__, __LINE__);//打印信息

    //注册函数（major，名称，结构体指针）
    major = register_chrdev(0,"DKB",&led_fops);


	/* ioremap 需要将物理地址映射为虚拟地址*/
	//虚拟地址 = ioremap(物理地址，映射大小)
	// IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 地址：0x02290000 + 0x14
	IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3 = ioremap(0x02290000 + 0x14, 4);
	
	// GPIO5_GDIR 地址：0x020AC004
	GPIO5_GDIR = ioremap(0x020AC004, 4);
	
	//GPIO5_DR 地址：0x020AC000
	GPIO5_DR  = ioremap(0x020AC000, 4);


    /* 创建了 类 和 device */
    led_class = class_creat(THIS_MODULE, "myled");
	device_create(led_class, NULL, MKDEV(major, 0), NULL, "myled"); /* /dev/myled */

    return 0;
}


/* 出口函数 */
static void __exit led_exit(void)
{
	//清除ioremap的结果
	iounmap(IOMUXC_SNVS_SW_MUX_CTL_PAD_SNVS_TAMPER3);
	iounmap(GPIO5_GDIR);
	iounmap(GPIO5_DR);

    /* 销毁 device 和 类 */
    device_destroy(led_class,  MKDEV(major, 0)); 
    class_destroy(led_class);

    unregister_chrdev(major,"DKB");
}

module_init(led_init);
module_init(led_exit);

MODULE_LICENSE("GPL");